/*
 * Individual.java
 *
 * Created on 13 de noviembre de 2006, 09:28 AM
 */

package cflp;

import shortestPath.*;

/**
 * Crea un individuo a partir de una red y las probabilidades que un nodo se convierta en una bodega, para asignar los nodos a las bodegas
 * abiertas se les da un orden a los nodos que no son bodegas y se asignan a traves de encontrar la ruta mas corta mediante la implentacion
 * del algoritmo de Djstra de Robert Sedgewick, Algorithms in Java. Part5, Graph algorithm.
 * @author tavobula
 */
public class Individuo {
    
    /**
     * La red que se esta anlalizando.
     * Crea una nueva instancia de un individuo.
     * @param n La red que se esta analizando.
     * @param p la probabilidad que un nodo se convierta en bodega
     *
     */
    
    private Network net;
    private double p;
    double[][]spc, spt;
    private Edge[][] edges;
    
    public Individuo(Network n, double p) {
        this.net=n;
        this.p=p;
        int arcos=n.getArcsNumber();
        spc=(new ConstructEdges(net.getCosts(),false,arcos)).getSP();
        spt=(new ConstructEdges(net.getDistances(),false,arcos)).getSP();
    }
    
    /**
     * Crea una nueva instancia de un individuo.
     * @param n La red que se esta analizando.
     */
    public Individuo(Network n) {
         this.net=n;
         int arcos=n.getArcsNumber();
         spc=(new ConstructEdges(net.getCosts(),false,arcos)).getSP();
         spt=(new ConstructEdges(net.getDistances(),false,arcos)).getSP();
    }
    
    
    /**
     *
     * @return El vector de tamaño N, nodos de la red, cada elemento del vector toma valores {0,1}. Uno si el nodo se convierte en bodega y cero en caso contrario
     */
    public int[] generateSolution2(){
        int n=net.getNodesNumber();
        int[] w= new int[n];
        for(int i=0;i<n;++i){
            w[i]=(Math.random()<p)?1:0;
        }
        int sumaw=0;
        java.util.Vector v=new java.util.Vector();
        int j=0;
        for(int i=0;i<w.length;++i){
            if(w[i]==1){
                sumaw=sumaw+net.getWarehouseCapacity()[i];
            }else{
                v.add(j,new Integer(i));
                j=j+1;
            }
        }
        while(sumaw<net.getDemTotal()){
            int a=(int) Math.floor(Math.random()*v.size());
            int pos=Integer.parseInt(v.get(a).toString());
            w[pos]=1;
            sumaw=sumaw+net.getWarehouseCapacity()[pos];
            v.remove(a);
        }
        //System.out.println("Capacidad Total "+sumaw);
        //System.out.println("Demanda Total "+net.getDemTotal());
        return w;
    }
    
    
    public int[] generateSolution(){
        int a=(int) Math.ceil(net.getDemTotal()*1d/net.getWarehouseCapacity()[0]*1d);
        int[] w= new int[net.getNodesNumber()];
        int b=(int) Math.floor(Math.random()*(w.length-a+1))+a;
        
        java.util.Vector v=new java.util.Vector();
        
        for(int i=0;i<w.length;++i){
            v.add(i,new Integer(i));
        }
        
        for(int i=0;i<b;++i){
            int apos=(int) Math.floor(Math.random()*v.size());
            int pos=Integer.parseInt(v.get(apos).toString());
            w[pos]=1;
            v.remove(apos);
        }
        
        //System.out.println("Capacidad Total "+sumaw);
        //System.out.println("Demanda Total "+net.getDemTotal());
        return w;
    }
    
    
    public int[][] servedNodes(int[] wn){
        
        int[][] servn=new int[net.getNodesNumber()][net.getNodesNumber()];
        for(int i=0;i<servn.length;++i){
            for(int j=0;j<servn[i].length;++j) servn[i][j]=0;
        }
        //se obtiene la demanda de los nodos
        int[] demand=new int[net.getNodesNumber()];
        System.arraycopy(net.getDemand(), 0, demand, 0, net.getNodesNumber());
        int[] asigCap=new int[net.getNodesNumber()];
        System.arraycopy(net.getWarehouseCapacity(), 0, asigCap, 0, net.getNodesNumber());
        
        int totalCap=0;
        int wnumber=0;
        //se asignan los nodos que se sirven asi mismo
        for(int i=0;i<wn.length;++i){
            if(wn[i]==1){
                totalCap=totalCap+asigCap[i];
                wnumber=wnumber+1;
                servn[i][i]=demand[i];
                asigCap[i]=asigCap[i]-demand[i];
            }
            if(wn[i]==0)asigCap[i]=0;
        }
        
        //se construye la red para asignar el problema
        
        int dest=(totalCap==net.getDemTotal())?(net.getNodesNumber()-wnumber):(net.getNodesNumber()-wnumber+1);
        
        int[][] e=new int[wnumber+wnumber*dest+dest][5];
        int ne=0;
        //se cosntruyen los ejes
        for(int w=0;w<wn.length;++w){
            if(wn[w]==1){
                e[ne][0]=0;
                e[ne][1]=w+1;
                e[ne][2]=asigCap[w];
                e[ne][3]=0;
                e[ne][4]=0;
                ne=ne+1;
                for(int i=0;i<wn.length;++i){
                    if(wn[i]==0){
                        e[ne][0]=w+1;
                        e[ne][1]=i+1;
                        e[ne][2]=totalCap;
                        e[ne][3]=(int)spc[w][i];
                        e[ne][4]=0;
                        ne=ne+1;
                    }
                }
            }else{
                e[ne][0]=w+1;
                e[ne][1]=wnumber+dest+1;
                e[ne][2]=demand[w];
                e[ne][3]=0;
                e[ne][4]=0;
                ne=ne+1;
            }
            
        }
        
        if(dest>net.getNodesNumber()-wnumber){
            e[ne][0]=dest+wnumber;
            e[ne][1]=wnumber+dest+1;
            e[ne][2]=totalCap-net.getDemTotal();
            e[ne][3]=0;
            e[ne][4]=0;
            ne=ne+1;
            for(int i=0;i<wn.length;++i){
                if(wn[i]==1){
                    e[ne][0]=i+1;
                    e[ne][1]=dest+wnumber;
                    e[ne][2]=totalCap;
                    e[ne][3]=0;
                    e[ne][4]=0;
                    ne=ne+1;
                }
            }
        }
        
        //for(int i=0;i<e.length;++i)System.out.println(e[i][0]+"\t"+e[i][1]+"\t"+e[i][2]+"\t"+e[i][3]+"\t"+e[i][4]);
        int[][] sol=networkFlow.GetSolution.solve(e, wnumber+dest+1);
        
        for(int i=0;i<net.getNodesNumber();i++){
            for(int j=0;j<net.getNodesNumber();j++){
                servn[i][j]=(sol[i+1][j+1]>0)?sol[i+1][j+1]:servn[i][j];
            }
        }
        
        
        return servn;
    }
    
    
    public void printAvailable(int [] a){
        for(int i=0;i<a.length;++i){
            if(a[i]>0){
                System.out.print(i+"->"+a[i]+" ");
            }
        }
        System.out.println("");
    }
    
    public int totalCost(int[] wn){
        int[][] sn=servedNodes(wn);
        int cf=0;
        int[] fixedCost=net.getFixedCosts();
        for(int i=0;i<wn.length;++i){
            if(wn[i]==1){
                cf=cf+fixedCost[i];
            }
        }
        //System.out.println(cf);
        int tc=0;
        for(int i=0;i<sn.length;++i){
            for(int j=0;j<sn[i].length;++j){
                if((sn[i][j]>=1)&&(i!=j)){
                    // System.out.println((spc[i][j]*sn[i][j]));
                    tc= tc+(int)(spc[i][j]*sn[i][j]);
                }
            }
        }
        return cf+tc;
    }
    
    public int cover(int[] wn){
        int[][] sn=servedNodes(wn);
        int cv=0;
        for(int i=0;i<sn.length;++i){
            for(int j=0;j<sn[i].length;++j){
                if((sn[i][j]>=1)&&(spt[j][i]<=25)){
                    cv=cv+sn[i][j];
                }
            }
        }
        return cv;
    }
    
}
